treeview: Call a11y functions for culmn changes directly
authorBenjamin Otte <otte@redhat.com>
Wed, 16 Nov 2011 02:47:33 +0000 (03:47 +0100)
committerBenjamin Otte <otte@redhat.com>
Wed, 16 Nov 2011 03:39:25 +0000 (04:39 +0100)
This way, the a11y code knows if a column was reordered, added or
removed and can do the right things instead of trying to guess and
getting it wrong.

Also, this patch finalizes the changes so that only visible columns
exist to the accessibility interface.

gtk/a11y/gtktreeviewaccessible.c
gtk/a11y/gtktreeviewaccessible.h
gtk/gtktreeview.c
gtk/gtktreeviewcolumn.c

index 9457cfc15c99085f712cad1df3ca5e4f826146b6..e3c6164ef5ffacd297764f6afcb833349611371b 100644 (file)
@@ -58,16 +58,11 @@ static void     size_allocate_cb     (GtkWidget        *widget,
 static void     selection_changed_cb (GtkTreeSelection *selection,
                                       gpointer          data);
 
-static void     columns_changed      (GtkTreeView      *tree_view);
 static void     cursor_changed       (GtkTreeView      *tree_view,
                                       GtkTreeViewAccessible *accessible);
 static gboolean focus_in             (GtkWidget        *widget);
 static gboolean focus_out            (GtkWidget        *widget);
 
-static void     column_visibility_changed
-                                     (GObject          *object,
-                                      GParamSpec       *param,
-                                      gpointer          user_data);
 static void     destroy_count_func   (GtkTreeView      *tree_view,
                                       GtkTreePath      *path,
                                       gint              count,
@@ -263,14 +258,12 @@ gtk_tree_view_accessible_initialize (AtkObject *obj,
   GtkTreeViewAccessible *accessible;
   GtkTreeView *tree_view;
   GtkTreeModel *tree_model;
-  GList *tv_cols, *tmp_list;
   GtkWidget *widget;
   GtkTreeSelection *selection;
 
   ATK_OBJECT_CLASS (_gtk_tree_view_accessible_parent_class)->initialize (obj, data);
 
   accessible = GTK_TREE_VIEW_ACCESSIBLE (obj);
-  accessible->col_data = NULL;
   accessible->focus_cell = NULL;
   accessible->old_hadj = NULL;
   accessible->old_vadj = NULL;
@@ -295,8 +288,6 @@ gtk_tree_view_accessible_initialize (AtkObject *obj,
   g_signal_connect (selection, "changed",
                     G_CALLBACK (selection_changed_cb), obj);
 
-  g_signal_connect (tree_view, "columns-changed",
-                    G_CALLBACK (columns_changed), NULL);
   g_signal_connect (tree_view, "cursor-changed",
                     G_CALLBACK (cursor_changed), accessible);
   g_signal_connect (tree_view, "focus-in-event",
@@ -305,7 +296,6 @@ gtk_tree_view_accessible_initialize (AtkObject *obj,
                     G_CALLBACK (focus_out), NULL);
 
   accessible->tree_model = tree_model;
-  accessible->n_cols = 0;
   if (tree_model)
     {
       g_object_add_weak_pointer (G_OBJECT (accessible->tree_model), (gpointer *)&accessible->tree_model);
@@ -324,19 +314,6 @@ gtk_tree_view_accessible_initialize (AtkObject *obj,
   g_signal_connect (widget, "notify::vadjustment",
                     G_CALLBACK (vadjustment_set_cb), accessible);
 
-  accessible->col_data = g_array_sized_new (FALSE, TRUE,
-                                            sizeof (GtkTreeViewColumn *), 0);
-
-  tv_cols = gtk_tree_view_get_columns (tree_view);
-  for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
-    {
-      accessible->n_cols++;
-      g_signal_connect (tmp_list->data, "notify::visible",
-                        G_CALLBACK (column_visibility_changed), tree_view);
-      g_array_append_val (accessible->col_data, tmp_list->data);
-    }
-  g_list_free (tv_cols);
-
   gtk_tree_view_set_destroy_count_func (tree_view,
                                         destroy_count_func,
                                         NULL, NULL);
@@ -357,17 +334,6 @@ gtk_tree_view_accessible_finalize (GObject *object)
   if (accessible->cell_infos)
     g_hash_table_destroy (accessible->cell_infos);
 
-  if (accessible->col_data)
-    {
-      GArray *array = accessible->col_data;
-
-     /* No need to free the contents of the array since it
-      * just contains pointers to the GtkTreeViewColumn
-      * objects that are in the GtkTreeView.
-      */
-      g_array_free (array, TRUE);
-    }
-
   G_OBJECT_CLASS (_gtk_tree_view_accessible_parent_class)->finalize (object);
 }
 
@@ -1767,126 +1733,6 @@ selection_changed_cb (GtkTreeSelection *selection,
     g_signal_emit_by_name (accessible, "selection-changed");
 }
 
-static void
-columns_changed (GtkTreeView *tree_view)
-{
-  AtkObject *atk_obj;
-  GtkTreeViewAccessible *accessible;
-  GList *tv_cols, *tmp_list;
-  gboolean column_found;
-  gboolean move_found = FALSE;
-  gint column_count = 0;
-  gint i;
-
-  atk_obj = gtk_widget_get_accessible (GTK_WIDGET(tree_view));
-  accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
-
-  /* This function must determine if the change is an add, delete
-   * or a move based upon its cache of TreeViewColumns in
-   * accessible->col_data
-   */
-  tv_cols = gtk_tree_view_get_columns (tree_view);
-  accessible->n_cols = g_list_length (tv_cols);
-
-  /* check for adds or moves */
-  for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
-    {
-      column_found = FALSE;
-
-      for (i = 0; i < accessible->col_data->len; i++)
-        {
-
-          if ((GtkTreeViewColumn *)tmp_list->data ==
-              (GtkTreeViewColumn *)g_array_index (accessible->col_data,
-               GtkTreeViewColumn *, i))
-            {
-              column_found = TRUE;
-
-              /* If the column isn't in the same position, a move happened */
-              if (!move_found && i != column_count)
-                {
-                  /* Just emit one column reordered signal when a move happens */
-                  g_signal_emit_by_name (atk_obj, "column-reordered");
-                  move_found = TRUE;
-                }
-
-              break;
-            }
-        }
-
-     /* If column_found is FALSE, then an insert happened for column
-      * number column_count
-      */
-      if (!column_found)
-        {
-          gint row;
-
-          /* Generate column-inserted signal */
-          g_signal_emit_by_name (atk_obj, "column-inserted", column_count, 1);
-
-          /* Generate children-changed signals */
-          for (row = 0; row < get_n_rows (tree_view); row++)
-            {
-             /* Pass NULL as the child object, i.e. 4th argument */
-              g_signal_emit_by_name (atk_obj, "children-changed::add",
-                                    ((row * accessible->n_cols) + column_count), NULL, NULL);
-            }
-        }
-
-      column_count++;
-    }
-
-  /* check for deletes */
-  for (i = 0; i < accessible->col_data->len; i++)
-    {
-      column_found = FALSE;
-
-      for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
-        {
-            if ((GtkTreeViewColumn *)tmp_list->data ==
-                (GtkTreeViewColumn *)g_array_index (accessible->col_data,
-                 GtkTreeViewColumn *, i))
-              {
-                column_found = TRUE;
-                break;
-              }
-        }
-
-       /* If column_found is FALSE, then a delete happened for column
-        * number i
-        */
-      if (!column_found)
-        {
-          gint row;
-
-          clean_cols (accessible,
-                      (GtkTreeViewColumn *)g_array_index (accessible->col_data,
-                      GtkTreeViewColumn *, i));
-
-          /* Generate column-deleted signal */
-          g_signal_emit_by_name (atk_obj, "column-deleted", i, 1);
-
-          /* Generate children-changed signals */
-          for (row = 0; row < get_n_rows (tree_view); row++)
-            {
-              /* Pass NULL as the child object, 4th argument */
-              g_signal_emit_by_name (atk_obj, "children-changed::remove",
-                                     ((row * accessible->n_cols) + column_count), NULL, NULL);
-            }
-        }
-    }
-
-  traverse_cells (accessible, NULL, FALSE);
-
-  /* rebuild the array */
-  g_array_free (accessible->col_data, TRUE);
-  accessible->col_data = g_array_sized_new (FALSE, TRUE, sizeof (GtkTreeViewColumn *), 0);
-
-  for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
-    g_array_append_val (accessible->col_data, tmp_list->data);
-  g_list_free (tv_cols);
-}
-
 static void
 cursor_changed (GtkTreeView           *tree_view,
                 GtkTreeViewAccessible *accessible)
@@ -2003,53 +1849,6 @@ model_row_changed (GtkTreeModel *tree_model,
   g_signal_emit_by_name (accessible, "visible-data-changed");
 }
 
-static void
-column_visibility_changed (GObject    *object,
-                           GParamSpec *pspec,
-                           gpointer    user_data)
-{
-  if (g_strcmp0 (pspec->name, "visible") == 0)
-    {
-      /* A column has been made visible or invisible
-       * We update our cache of cells and emit model_changed signal
-       */
-      GtkTreeView *tree_view = (GtkTreeView *)user_data;
-      GtkTreeViewAccessible *accessible;
-      GtkTreeViewAccessibleCellInfo *cell_info;
-      GtkTreeViewColumn *this_col = GTK_TREE_VIEW_COLUMN (object);
-      GtkTreeViewColumn *tv_col;
-      GHashTableIter iter;
-
-      accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (tree_view))
-);
-      g_signal_emit_by_name (accessible, "model-changed");
-
-      g_hash_table_iter_init (&iter, accessible->cell_infos);
-      while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&cell_info))
-        {
-          tv_col = cell_info->cell_col_ref;
-          if (tv_col == this_col)
-            {
-              GtkTreePath *row_path;
-              row_path = cell_info_get_path (cell_info);
-              if (GTK_IS_RENDERER_CELL_ACCESSIBLE (cell_info->cell))
-                {
-                  if (gtk_tree_view_column_get_visible (tv_col))
-                      set_cell_visibility (tree_view,
-                                           cell_info->cell,
-                                           tv_col, row_path, FALSE);
-                  else
-                    {
-                      _gtk_cell_accessible_remove_state (cell_info->cell, ATK_STATE_VISIBLE, TRUE);
-                      _gtk_cell_accessible_remove_state (cell_info->cell, ATK_STATE_SHOWING, TRUE);
-                    }
-                }
-              gtk_tree_path_free (row_path);
-            }
-        }
-    }
-}
-
 static void
 model_row_inserted (GtkTreeModel *tree_model,
                     GtkTreePath  *path,
@@ -3053,37 +2852,33 @@ disconnect_model_signals (GtkTreeViewAccessible *accessible)
 }
 
 /* Returns the column number of the specified GtkTreeViewColumn
- *
- * If visible is set, the value returned will be the visible column number,
- * i.e. suitable for use in AtkTable function. If visible is not set, the
- * value returned is the actual column number, which is suitable for use in
- * getting an index value.
+ * The column must be visible.
  */
 static gint
-get_column_number (GtkTreeView       *tree_view,
+get_column_number (GtkTreeView       *treeview,
                    GtkTreeViewColumn *column)
 {
-  GtkTreeViewColumn *tv_column;
-  gint ret_val;
-  gint i;
-  AtkObject *atk_obj;
-  GtkTreeViewAccessible *accessible;
+  GtkTreeViewColumn *cur;
+  guint i, number;
 
-  atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
-  accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
+  number = 0;
 
-  ret_val = 0;
-  for (i = 0; i < accessible->col_data->len; i++)
+  for (i = 0; i < gtk_tree_view_get_n_columns (treeview); i++)
     {
-      tv_column = g_array_index (accessible->col_data, GtkTreeViewColumn *, i);
-      if (tv_column == column)
+      cur = gtk_tree_view_get_column (treeview, i);
+      
+      if (!gtk_tree_view_column_get_visible (cur))
+        continue;
+
+      if (cur == column)
         break;
-      ret_val++;
+
+      number++;
     }
-  if (i == accessible->col_data->len)
-    ret_val = -1;
 
-  return ret_val;
+  g_return_val_if_fail (i < gtk_tree_view_get_n_columns (treeview), 0);
+
+  return number;
 }
 
 static gint
@@ -3314,3 +3109,156 @@ _gtk_tree_view_accessible_remove (GtkTreeView *treeview,
     }
 }
 
+/* NB: id is not checked, only columns < id are.
+ * This is important so the function works for notification of removal of a column */
+guint
+to_visible_column_id (GtkTreeView *treeview,
+                      guint        id)
+{
+  guint i;
+  guint invisible;
+
+  invisible = 0;
+
+  for (i = 0; i < id; i++)
+    {
+      GtkTreeViewColumn *column = gtk_tree_view_get_column (treeview, i);
+
+      if (!gtk_tree_view_column_get_visible (column))
+        invisible++;
+    }
+
+  return id - invisible;
+}
+
+void
+_gtk_tree_view_accessible_do_add_column (GtkTreeViewAccessible *accessible,
+                                         GtkTreeView           *treeview,
+                                         GtkTreeViewColumn     *column,
+                                         guint                  id)
+{
+  guint row, n_rows, n_cols;
+
+  /* Generate column-inserted signal */
+  g_signal_emit_by_name (accessible, "column-inserted", id, 1);
+
+  n_rows = get_n_rows (treeview);
+  n_cols = get_n_columns (treeview);
+
+  /* Generate children-changed signals */
+  for (row = 0; row <= n_rows; row++)
+    {
+     /* Pass NULL as the child object, i.e. 4th argument */
+      g_signal_emit_by_name (accessible, "children-changed::add",
+                             (row * n_cols) + id, NULL, NULL);
+    }
+
+  traverse_cells (accessible, NULL, FALSE);
+}
+
+void
+_gtk_tree_view_accessible_add_column (GtkTreeView       *treeview,
+                                      GtkTreeViewColumn *column,
+                                      guint              id)
+{
+  AtkObject *obj;
+
+  if (!gtk_tree_view_column_get_visible (column))
+    return;
+
+  obj = _gtk_widget_peek_accessible (GTK_WIDGET (treeview));
+  if (obj == NULL)
+    return;
+
+  _gtk_tree_view_accessible_do_add_column (GTK_TREE_VIEW_ACCESSIBLE (obj),
+                                           treeview,
+                                           column,
+                                           to_visible_column_id (treeview, id));
+}
+
+void
+_gtk_tree_view_accessible_do_remove_column (GtkTreeViewAccessible *accessible,
+                                            GtkTreeView           *treeview,
+                                            GtkTreeViewColumn     *column,
+                                            guint                  id)
+{
+  guint row, n_rows, n_cols;
+
+  clean_cols (accessible, column);
+
+  /* Generate column-deleted signal */
+  g_signal_emit_by_name (accessible, "column-deleted", id, 1);
+
+  n_rows = get_n_rows (treeview);
+  n_cols = get_n_columns (treeview);
+
+  /* Generate children-changed signals */
+  for (row = 0; row <= n_rows; row++)
+    {
+      /* Pass NULL as the child object, 4th argument */
+      g_signal_emit_by_name (accessible, "children-changed::remove",
+                             (row * n_cols) + id, NULL, NULL);
+    }
+
+  traverse_cells (accessible, NULL, FALSE);
+}
+
+void
+_gtk_tree_view_accessible_remove_column (GtkTreeView       *treeview,
+                                         GtkTreeViewColumn *column,
+                                         guint              id)
+{
+  AtkObject *obj;
+
+  if (!gtk_tree_view_column_get_visible (column))
+    return;
+
+  obj = _gtk_widget_peek_accessible (GTK_WIDGET (treeview));
+  if (obj == NULL)
+    return;
+
+  _gtk_tree_view_accessible_do_remove_column (GTK_TREE_VIEW_ACCESSIBLE (obj),
+                                              treeview,
+                                              column,
+                                              to_visible_column_id (treeview, id));
+}
+
+void
+_gtk_tree_view_accessible_reorder_column (GtkTreeView       *treeview,
+                                          GtkTreeViewColumn *column)
+{
+  AtkObject *obj;
+
+  obj = _gtk_widget_peek_accessible (GTK_WIDGET (treeview));
+  if (obj == NULL)
+    return;
+
+  g_signal_emit_by_name (obj, "column-reordered");
+
+  traverse_cells (GTK_TREE_VIEW_ACCESSIBLE (obj), NULL, FALSE);
+}
+
+void
+_gtk_tree_view_accessible_toggle_visibility (GtkTreeView       *treeview,
+                                             GtkTreeViewColumn *column)
+{
+  AtkObject *obj;
+  guint id;
+
+  obj = _gtk_widget_peek_accessible (GTK_WIDGET (treeview));
+  if (obj == NULL)
+    return;
+
+  id = get_column_number (treeview, column);
+
+  if (gtk_tree_view_column_get_visible (column))
+    _gtk_tree_view_accessible_do_add_column (GTK_TREE_VIEW_ACCESSIBLE (obj),
+                                             treeview,
+                                             column,
+                                             id);
+  else
+    _gtk_tree_view_accessible_do_remove_column (GTK_TREE_VIEW_ACCESSIBLE (obj),
+                                                treeview,
+                                                column,
+                                                id);
+}
index 00e969a034582cae02c703ffa4bf5741069dbc0b..15f7c55d5738ee28eaff08f993abf41d780e5c7d 100644 (file)
@@ -40,8 +40,6 @@ struct _GtkTreeViewAccessible
   GtkContainerAccessible parent;
 
   gint           n_children_deleted;
-  gint           n_cols;
-  GArray*        col_data;
   GHashTable    *cell_infos;
   GtkTreeModel  *tree_model;
   AtkObject     *focus_cell;
@@ -63,6 +61,18 @@ void            _gtk_tree_view_accessible_remove        (GtkTreeView       *tree
                                                          GtkRBTree         *tree,
                                                          GtkRBNode         *node);
 
+void            _gtk_tree_view_accessible_add_column    (GtkTreeView       *treeview,
+                                                         GtkTreeViewColumn *column,
+                                                         guint              id);
+void            _gtk_tree_view_accessible_remove_column (GtkTreeView       *treeview,
+                                                         GtkTreeViewColumn *column,
+                                                         guint              id);
+void            _gtk_tree_view_accessible_reorder_column(GtkTreeView       *treeview,
+                                                         GtkTreeViewColumn *column);
+void            _gtk_tree_view_accessible_toggle_visibility
+                                                        (GtkTreeView       *treeview,
+                                                         GtkTreeViewColumn *column);
+
 G_END_DECLS
 
 #endif /* __GTK_TREE_VIEW_ACCESSIBLE_H__ */
index 9d75737ed608291f778cf41da205f94a1d3987c8..d411f5b690d96f1e26cf7b5aec2014afcc9cc8e5 100644 (file)
@@ -11922,6 +11922,8 @@ gint
 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
                              GtkTreeViewColumn *column)
 {
+  guint position;
+
   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == GTK_WIDGET (tree_view), -1);
@@ -11946,6 +11948,8 @@ gtk_tree_view_remove_column (GtkTreeView       *tree_view,
 
   _gtk_tree_view_column_unset_tree_view (column);
 
+  position = g_list_index (tree_view->priv->columns, column);
+
   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
   tree_view->priv->n_columns--;
 
@@ -11972,6 +11976,8 @@ gtk_tree_view_remove_column (GtkTreeView       *tree_view,
 
   _gtk_tree_view_reset_header_styles (tree_view);
 
+  _gtk_tree_view_accessible_remove_column (tree_view, column, position);
+
   g_object_unref (column);
   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
 
@@ -12004,6 +12010,9 @@ gtk_tree_view_insert_column (GtkTreeView       *tree_view,
     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
 
+  if (position < 0 || position > tree_view->priv->n_columns)
+    position = tree_view->priv->n_columns;
+
   g_object_ref_sink (column);
 
   if (tree_view->priv->n_columns == 0 &&
@@ -12038,6 +12047,9 @@ gtk_tree_view_insert_column (GtkTreeView       *tree_view,
     }
 
   _gtk_tree_view_reset_header_styles (tree_view);
+
+  _gtk_tree_view_accessible_add_column (tree_view, column, position);
+
   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
 
   return tree_view->priv->n_columns;
@@ -12254,6 +12266,9 @@ gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
     }
 
   _gtk_tree_view_reset_header_styles (tree_view);
+
+  _gtk_tree_view_accessible_reorder_column (tree_view, column);
+
   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
 }
 
index 7dd5c539c5a11e2085bfe0bd171523dfb828c526..a7900dbef7d42eb6f79861373b2f887587a7f007 100644 (file)
@@ -37,6 +37,7 @@
 #include "gtkprivate.h"
 #include "gtkintl.h"
 #include "gtktypebuiltins.h"
+#include "a11y/gtktreeviewaccessible.h"
 
 
 /**
@@ -1937,7 +1938,11 @@ gtk_tree_view_column_set_visible (GtkTreeViewColumn *tree_column,
     _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
 
   if (priv->tree_view)
-    _gtk_tree_view_reset_header_styles (GTK_TREE_VIEW (priv->tree_view));
+    {
+      _gtk_tree_view_reset_header_styles (GTK_TREE_VIEW (priv->tree_view));
+      _gtk_tree_view_accessible_toggle_visibility (GTK_TREE_VIEW (priv->tree_view),
+                                                   tree_column);
+    }
 
   gtk_tree_view_column_update_button (tree_column);
   g_object_notify (G_OBJECT (tree_column), "visible");